package ma.jeetconsulting.pocs.service;

import java.util.ArrayList;
import java.util.List;

import ma.jeetconsulting.pocs.domain.Dependency;
import ma.jeetconsulting.pocs.persistence.AlertResolverRepository;
import ma.jeetconsulting.pocs.persistence.DependencyRepository;

import org.drools.KnowledgeBase;
import org.drools.KnowledgeBaseFactory;
import org.drools.builder.KnowledgeBuilder;
import org.drools.builder.KnowledgeBuilderError;
import org.drools.builder.KnowledgeBuilderErrors;
import org.drools.builder.KnowledgeBuilderFactory;
import org.drools.builder.ResourceType;
import org.drools.io.impl.ClassPathResource;
import org.drools.runtime.StatefulKnowledgeSession;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.sonatype.aether.artifact.Artifact;
import org.sonatype.aether.graph.DependencyNode;

public class DroolsConflectsChecker implements ConflectsChecker {

	private static final String GLOBAL_VAR_RESULT = "result";
	private static final String GLOBAl_VAR_DEPENDENCY_DAO = "alertResolverRepository";
	private static final String RULES_FILE_NAME = "conflectsRules.drl";
	private Logger logger = LoggerFactory.getLogger(getClass());

	private AlertResolverRepository alertResolverRepository;
	private DependencyRepository dependencyRepository;
	private KnowledgeBuilder builder;
	private KnowledgeBase base;

	@Override
	public Solution getSolutionFor(EventuelConflect conflect) {
		List<Solution> resultHolder = new ArrayList<>();
		StatefulKnowledgeSession session = null;
		try {
			session = getStatefullSession(resultHolder);
			addConflectToSessionAndLunchChecking(conflect, session);
		} finally {
			if (session != null)
				session.dispose();
		}

		if (resultHolder.size() != 0)
			return resultHolder.get(0);

		return null;
	}

	private void addConflectToSessionAndLunchChecking(
			EventuelConflect conflect, StatefulKnowledgeSession session) {
		Long id1 = createDependency(conflect.getModuleNode()).getId();
		Long id2 = createDependency(conflect.getCheckedNode()).getId();
		conflect.setDependencyId1(id1);
		conflect.setDependencyId2(id2);
		try {
			session.insert(conflect);
		} catch (Exception e) {
			logger.error("An error occur : ", e);
		}
		session.fireAllRules();
	}

	private StatefulKnowledgeSession getStatefullSession(
			List<Solution> resultHolder) {
		KnowledgeBase base = getKnowledgeBase();
		StatefulKnowledgeSession session = base.newStatefulKnowledgeSession();

		session.setGlobal(GLOBAl_VAR_DEPENDENCY_DAO, alertResolverRepository);
		session.setGlobal(GLOBAL_VAR_RESULT, resultHolder);

		return session;
	}

	private KnowledgeBase getKnowledgeBase() {
		if (builder == null || base == null) {
			builder = KnowledgeBuilderFactory.newKnowledgeBuilder();
			builder.add(new ClassPathResource(RULES_FILE_NAME),
					ResourceType.DRL);

			checkIfThereIsAnyParsingError(builder);

			base = KnowledgeBaseFactory.newKnowledgeBase();
			base.addKnowledgePackages(builder.getKnowledgePackages());
		}
		return base;
	}

	private void checkIfThereIsAnyParsingError(KnowledgeBuilder builder) {
		KnowledgeBuilderErrors errors = builder.getErrors();
		if (errors.size() > 0) {
			for (KnowledgeBuilderError error : errors) {
				logger.error("Drools error : ", error);
			}
			throw new IllegalArgumentException("Could not parse knowledge.");
		}
	}

	
	private Dependency createDependency(DependencyNode moduleNode) {
		Artifact artifact = moduleNode.getDependency().getArtifact();
		Dependency dependency = dependencyRepository.findDependency(
				artifact.getGroupId(), artifact.getArtifactId(),
				artifact.getVersion());
		return dependency;
	}

	public AlertResolverRepository getAlertResolverRepository() {
		return alertResolverRepository;
	}

	public void setAlertResolverRepository(
			AlertResolverRepository alertResolverRepository) {
		this.alertResolverRepository = alertResolverRepository;
	}

}
